package http

import (
	"gitee.com/captials-team/ubdframe/src/common/utils"
	"gitee.com/captials-team/ubdframe/src/domain/configstc"
	"gitee.com/captials-team/ubdframe/src/domain/dto/reqdata"
	"gitee.com/captials-team/ubdframe/src/domain/dto/respdata"
	"gitee.com/captials-team/ubdframe/src/domain/interfaces"
	"gitee.com/captials-team/ubdframe/src/domain/models"
	v1log "gitee.com/captials-team/ubdframe/src/pkg/logs"
	"gitee.com/captials-team/ubdframe/src/pkg/messages"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

type VerifyCodeController struct {
	l v1log.ILog

	phoneSender messages.MessageSender
	emailSender messages.MessageSender

	verifyCodeDao interfaces.ItfVerifyCode

	codeExpireTime time.Duration //过期时间
}

// SendCode godoc
// @Summary      短信验证码-发送
// @Description  发送短信验证码
// @Tags         user.other
// @Produce      json
// @Security     ApiKeyAuth
// @Param        param    body     reqdata.PhoneEmailSendReq  true  "发送对象信息"
// @success 200  {object} respdata.ResponseData{data=respdata.SmsCodeSendResp} "发送成功"
// @success 500 {object} respdata.ResponseData{} "发送失败"
// @Router       /verify_code/send [post]
func (ctr *VerifyCodeController) SendCode(ctx *gin.Context) {
	var req reqdata.PhoneEmailSendReq
	ctx.ShouldBind(&req)

	//发送
	var sender messages.MessageSender
	var target string
	if req.Phone != "" {
		sender = ctr.phoneSender
		target = req.Phone
	} else if req.Email != "" {
		//邮箱验证码
		sender = ctr.emailSender
		target = req.Email
	}
	if sender == nil {
		ctx.JSON(http.StatusOK, respdata.CNotSupport)
		return
	}
	if !sender.Allow(target) {
		ctx.JSON(http.StatusOK, respdata.CError.MMsg("wait for seconds send"))
		return
	}
	expireTime := ctr.codeExpireTime
	expiredAt := time.Now().Add(expireTime)
	code := utils.RandFigureCode(6)

	ctr.l.Info("code send: %s,%s", target, code)

	go func() {
		codeInfo := &models.VerifyCode{
			Target:    target,
			Code:      code,
			ExpiredAt: &expiredAt,
		}
		//存dao
		if _, err := ctr.verifyCodeDao.Add(codeInfo); err != nil {
			ctx.JSON(http.StatusOK, respdata.CError.MMsg("wait for seconds send"))
			return
		}
		//发送实际处理
		if err := sender.Send(target, code); err != nil {
			ctr.l.Error("send code err: %s,%s", target, err)
		}
		ctr.l.Info("code-%s send success", target)
	}()

	ctx.JSON(http.StatusOK, respdata.CSuccess.MData(respdata.SmsCodeSendResp{
		ValidMinute: int64(expireTime / time.Second),
		Target:      target,
	}))
}

// VerifyCode godoc
// @Summary      短信验证码-校验
// @Description  校验短信验证码
// @Tags         user.other
// @Produce      json
// @Security     ApiKeyAuth
// @Param        param    body     reqdata.PhoneEmailVerifyReq  true  "验证信息"
// @success 0  {object} respdata.ResponseData{data=respdata.SmsCodeVerifyResp} "验证成功"
// @success 5 {object} respdata.ResponseData{} "验证失败"
// @Router       /verify_code/verify [post]
func (ctr *VerifyCodeController) VerifyCode(ctx *gin.Context) {
	var req reqdata.PhoneEmailVerifyReq

	ctx.ShouldBindBodyWithJSON(&req)

	if req.Target() == "" || req.Code == "" {
		ctx.JSON(http.StatusOK, respdata.CParamsInvalid)
		return
	}

	//校验验证码
	ok, err := ctr.verifyCodeDao.Verify(req.Target(), req.Code)
	if err != nil || !ok {
		ctr.l.Ctl(err != nil).Error("verify err %s", err)
		ctx.JSON(http.StatusOK, respdata.CVtCodeInvalid)
		return
	}

	ctx.JSON(http.StatusOK, respdata.CSuccess.MData(respdata.SmsCodeVerifyResp{
		Target:  req.Target(),
		Success: true,
	}))
}

func (ctr *VerifyCodeController) VerifyHandler() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var req reqdata.PhoneEmailVerifyReq

		ctx.ShouldBindBodyWithJSON(&req)

		if req.Target() == "" || req.Code == "" {
			ctx.JSON(http.StatusOK, respdata.CParamsInvalid)
			return
		}

		//校验验证码
		ok, err := ctr.verifyCodeDao.Verify(req.Target(), req.Code)
		if err != nil || !ok {
			ctr.l.Ctl(err != nil).Error("verify err %s", err)
			ctx.AbortWithStatusJSON(http.StatusOK, respdata.CVtCodeInvalid)
			return
		}
	}
}

func NewVerifyCodeController(conf *configstc.UserAppConfig, l v1log.ILog, verifyCodeDao interfaces.ItfVerifyCode) *VerifyCodeController {
	ctr := &VerifyCodeController{
		l: l,

		phoneSender: messages.NewNoneSender(),
		emailSender: messages.NewNoneSender(),

		codeExpireTime: time.Minute * 5,
	}
	//sms
	if conf.SmsConfig.Enable {
		ctr.phoneSender = messages.NewAliCloudCodeSMS(conf.SmsConfig)
	}
	//邮箱
	if conf.EmailConfig.Enable {
		ctr.emailSender = messages.NewEmailVerifyCodeSender(&conf.EmailConfig).WithCodeExpired(ctr.codeExpireTime)
	}

	ctr.verifyCodeDao = verifyCodeDao

	return ctr
}
